package managers;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import entities.Adminstrator;
import entities.Comment;
import entities.Event;
import entities.Message;
import entities.Propietary;
import entities.User;
import exception.ValidationException;

import tools.beans.Md5Bean;

@Stateless
public class EntityManagerAux {

	@PersistenceContext
	private EntityManager m;
	
	public enum LoginResult{
		SUCCESS, NEEDS_VALIDATION, FAILURE
	}
	
	public LoginResult login(String id, String pass){
        User user = m.find(User.class, id);
        
        if(user == null)	//doesn't exist
        	return LoginResult.FAILURE;
        
        else{	//exists
        	String passHash = encode(pass);
        	if(user.getPass().equals(passHash))	//exists, pass ok
        		if(user.getValidated() == 0)	//needs validation
        			return LoginResult.NEEDS_VALIDATION;
        	
        		else	//validated
        			return LoginResult.SUCCESS; 
        	
        	else	//wrong pass
        		return LoginResult.FAILURE;
        }
	}
	
	public LoginResult loginAdmin(String id, String pass){
        Adminstrator user = m.find(Adminstrator.class, id);
        
        if(user == null)	//doesn't exist
        	return LoginResult.FAILURE;
        
        else{	//exists
        	String passHash = encode(pass);
        	if(user.getPass().equals(passHash))	//exists, pass ok
        		//validated
        		return LoginResult.SUCCESS; 
        	
        	else	//wrong pass
        		return LoginResult.FAILURE;
        }
	}
	
	
	public boolean exists(String id) {
        Query query = m.createQuery("SELECT u FROM User u WHERE u.user=:id");
        query.setParameter("id", id);
        try{
        User c = (User) query.getSingleResult();
        if (c==null){return false;}
        return true;
        }
        catch(Exception e){
        	return false;
        }
	}
	
	/**
	 * La function pour ajouter les utilisateurs, on utilise un manager pour
	 * garder
	 * @param id
	 * @param name
	 * @param pass
	 * @param surname
	 * @param mail
	 * @param sex
	 * @param age
	 */
	
	public void addUser(String id, String name, String pass, String surname,String mail, String sex, String age){
		
			int ageAux = Integer.parseInt(age);
			
			//Create user
			User user = new User();
			user.setUser(id);
			user.setSurname(surname);
			user.setName(name);
			user.setMail(mail);
			user.setPass(pass);
			user.setAge(ageAux);
			user.setSex(sex);
			user.setValidated((byte) 0); //Not yet validated
			m.persist(user);
	}
	
	/**
	 * La fonction pour ajouter a la base des donnes, un administrateur
	 * @param admin
	 * @param mail
	 * @param name
	 * @param pass
	 * @param phone
	 * @param surname
	 */
	
	public void addAdmin(String admin,String mail, String name, String pass, String phone, String surname ) {
		Adminstrator admin2 = new Adminstrator();
		
		admin2.setAdmin(admin);
		admin2.setMail(mail);
		admin2.setName(name);
		admin2.setPass(pass);
		admin2.setPhone(phone);
		admin2.setSurname(surname);
		m.persist(admin2);
		
	}
	
	/**
	 * La fonction pour ajouter a la base des donnes, un propietaire
	 * 
	 * @param admin
	 * @param mail
	 * @param name
	 * @param pass
	 * @param phone
	 * @param surname
	 */
	
	public void addPropietary(String admin,String mail, String name, String pass, String phone, String surname ) {
		Propietary admin2 = new Propietary();
		
		admin2.setBoss(admin);
		admin2.setMail(mail);
		admin2.setName(name);
		admin2.setPass(pass);
		admin2.setPhone(phone);
		admin2.setSurname(surname);
		m.persist(admin2);
		
	}
	
	/**
	 * Le methode mets a jour les utilisateurs qui seront validees.
	 * @param users
	 */
	public void validateUsers(List<User> users) {
		for(int i=0; i<users.size(); i++) {
			String name=users.get(i).getUser();
			Query l = m.createQuery("UPDATE User SET validated=1 where user='"+name+"'");
			int d = l.executeUpdate();
		}
	}
	
	/**
	 * Le methode mets a jour les utilisateurs qui seront bannes.
	 * @param users
	 */
	public void banUsers(List<User> users) {
		for(int i=0; i<users.size(); i++) {
			String name=users.get(i).getUser();
			Query l = m.createQuery("UPDATE User SET validated=0 where user='"+name+"'");
			int d = l.executeUpdate();
		}
	}
	
	/**
	 * Le methode mets a jour les eventments qui seront validees.
	 * @param events
	 */
	public void validateEvent(List<Event> events) {
		for(int i=0; i<events.size(); i++) {
			int a=events.get(i).getIdEvent();
			String name = ""+a;
			Query l = m.createQuery("UPDATE Event SET open=1 where idEvent='"+name+"'");
			int d = l.executeUpdate();
		}
	}
	
	/**
	 * Le methode mets a jour l'information d'un utilisateur.
	 * @param user
	 * @param surname
	 * @param name
	 * @param mail
	 */
	public void updateUser(String user, String surname, String name, String mail) {
		Query q= m.createQuery("UPDATE User SET surname = :sur , name = :nam , mail = :mai where user = :use");
		q.setParameter("sur", surname);
		q.setParameter("nam", name);
		q.setParameter("mai",mail);
		q.setParameter("use",user);
		int a = q.executeUpdate();
	}
	
	/**
	 * Fonction pour envoyer messages a un utilisateur. D'abord on contabilise le nombre
	 * messages, et apres on ajoute un message.
	 * @param recipient
	 * @param header
	 * @param message
	 * @param user
	 */
	public void sendMessage(String recipient, String header, String message, String user) {
		System.out.println(recipient);
		Query q = m.createQuery("SELECT COUNT(m.idMessage) from Message m");
		Number countResult=(Number) q.getSingleResult();
		System.out.println(countResult);
		Message mes= new Message();
		mes.setAsunto(message);
		mes.setHeader(header);
		mes.setUser_user(recipient);
		mes.setSender(user);
		mes.setIdMessage(countResult.intValue()+1);
		m.persist(mes);
		
	}
	
	/**
	 * Fonction pour cripter le mot de passe des utilisateurs.
	 * @param password
	 * @return String
	 */
    public String encode(String password) {
        byte[] uniqueKey = password.getBytes();
        byte[] hash      = null;

        try {
            hash = MessageDigest.getInstance("MD5").digest(uniqueKey);
        } catch (NoSuchAlgorithmException e) {
            throw new Error("No MD5 support in this VM.");
        }

        StringBuilder hashString = new StringBuilder();
        for (int i = 0; i < hash.length; i++) {
            String hex = Integer.toHexString(hash[i]);
            if (hex.length() == 1) {
                hashString.append('0');
                hashString.append(hex.charAt(hex.length() - 1));
            } else {
                hashString.append(hex.substring(hex.length() - 2));
            }
        }
        return hashString.toString();
    }
    
    
    /**
     * Retourne tous les eventments.
     * @param id
     * @return Event
     */
	public Event chercherEvent(String id) {
        if (id.equals(null) || "".equals(id)) {
            throw new ValidationException("<li>Identifiant invalide</li>");
        }
        Event event = m.find(Event.class, Integer.valueOf(id));
        return event;
	}
    
	/**
	 * Creation d'un commentaire, on le mets dans la base des donnes. Et apres on 
	 * envoi 
	 * @param idEvent
	 * @param idUser
	 * @param message
	 * @return Comment
	 */
    public Comment creerComment(String idEvent, String idUser, String message) {
        if (idEvent.equals(null) || "".equals(idEvent)) {
            throw new ValidationException("Identifiant Event invalide");
        }
        if (idUser.equals(null) || "".equals(idUser)) {
            throw new ValidationException("Identifiant User invalide");
        }
        if (message.equals(null) || "".equals(message)) {
            throw new ValidationException("Comment invalide");
        }
        User user = m.find(entities.User.class, String.valueOf(idUser));
        Event event = m.find(Event.class, Integer.valueOf(idEvent));
        Comment comment = new Comment();
        comment.setEvent(event);
        comment.setUser(user);
        comment.setComment(message);

        m.persist(comment);
        event.addComment(comment);
        user.addComment(comment);
        m.merge(event);
        m.merge(user);

        return comment;
    }
    
    /**
     * Chercher tous le commentaires qui sont valides.
     * @return
     */
    public List<Comment> searchValidatedComments() {
        Query query = m.createQuery("SELECT c FROM Comment c WHERE c.valide=:bool");
        query.setParameter("bool", true);
        List<Comment> comments = query.getResultList();
        return comments;
    }
    
    /**
     * Lorsque un administrateur veut valider des commentaires, on utilise cette fonction
     * @return
     */
    public List<Comment> searchUnvalidatedComments() {
        Query query = m.createQuery("SELECT c FROM Comment c WHERE c.valide=:bool");
        query.setParameter("bool", false);
        List<Comment> comments = (List<Comment>) query.getResultList();
        return comments;
    }

    /**
     * Chercher les eventments selon le eventment
     * @param idEvent
     * @return
     */
    public List<Comment> searchCommentsByEvent(String idEvent){
        if (idEvent.equals(null) || "".equals(idEvent)) {
            throw new ValidationException("Event invalide");
        }
        Event t = m.find(Event.class, Integer.valueOf(idEvent));
        Query query = m.createQuery("SELECT c FROM Comment c WHERE c.event = :event");
        query.setParameter("event", t);
        List<Comment> comments = query.getResultList();
        return comments;

    }
}
